; Begin code

Win := Object()

; Load window settings from ini file
initializeini("WindowList.ini")
loadini("WindowList.ini")

; Initialise variables
LockCount := 0

; Start Infinite loop!
Loop {
  ; Go through each section in the .ini
  Loop %inisections% {
    ; Get section name
    sec := section%A_Index%
    ; Pull 'WindowTitle' and 'WindowClass' keys to see what window we are looking for
    WinTitle := %sec%_WindowTitle
    WinClass := %sec%_WindowClass
    ; Remove built-in delay for window operations - we can put in our own delay
    SetWinDelay, 0
    ; If the 'MatchMode' key is specified, set the TitleMatchMode.
    if %sec%_MatchMode = "Start"
      SetTitleMatchMode 1
    if %sec%_MatchMode = "Contains"
      SetTitleMatchMode 2
    if %sec%_MatchMode = "Exact"
      SetTitleMatchMode 3
    if %sec%_MatchMode = "RegEx"
      SetTitleMatchMode RegEx
    ; Check if we can find a window matching the provided arguments.
    If WinExist(WinClass <> "" ? WinTitle . " ahk_class " . WinClass : WinTitle) {
      ; Now get the Window Handle (since we save our variables based on this)
      WinGet, ID, ID,
      ; Let's get the Process Name to check that it matches our 'Process' key if given
      WinGet, ProcessName, ProcessName,
      ; Check if we've already done what we needed to with this window
      If (!Win[ID]["AutoDone"]) and (%sec%_WindowProcess = "" or %sec%_WindowProcess = ProcessName) {
        ; Get lots of information about the window and remember it for later use
        WinGet, Style, Style,
        WinGetPos, X, Y, Width, Height,
        Win[ID,"Style"] := Style
        Win[ID,"Left"] := X
        Win[ID,"Top"] := Y
        Win[ID,"Width"] := Width
        Win[ID,"Height"] := Height
        ; We'll put in our override coordinates/dimensions from the .ini here if they exist
        if %sec%_X <> ""
          Win[ID,"Left"] := %sec%_X
        if %sec%_Y <> ""
          Win[ID,"Top"] := %sec%_Y
        if %sec%_Width <> ""
          Win[ID,"Width"] := %sec%_Width
        if %sec%_Height <> ""
          Win[ID,"Height"] := %sec%_Height
        ; If at least one coordinate or dimension was provided, let's apply them now.
        ; Since we've saved these values already, we don't need to do anything if it's going fullscreen anyway.
        if (%sec%_X or %sec%_Y or %sec%_Width or %sec%_Height) and (%sec%_Fullscreen <> "true" and !Win[ID]["Fullscreen"]) {
          ; Sleep for 10ms or whatever is provided in the 'Delay' key.
          Sleep % %sec%_Delay >= 0 ? %sec%_Delay : 10
          ; Do the move/resize
          WinMove, , , % Win[ID]["Left"], % Win[ID]["Top"], % Win[ID]["Width"], % Win[ID]["Height"]
          ; We won't need these variables anymore so we may as well free them
          Win[ID].Remove("Style")
          Win[ID].Remove("Left")
          Win[ID].Remove("Top")
          Win[ID].Remove("Width")
          Win[ID].Remove("Height")
          Win[ID].Remove("Fullscreen")
        }
        ; We can stop repeating now, unless the code below decides otherwise.
        Win[ID,"AutoDone"] := true
        ; Now check if it needs to go fullscreen and isn't already
        if (%sec%_Fullscreen = "true" and !Win[ID]["Fullscreen"]) {
          if ((%width%%height% <> %a_screenwidth%%a_screenheight%) or (Style & 0xC00000)) {
            ; Check if the window is active because it may have given incorrect dimensions and thus we may not need to do anything here anyway; especially if it's a fullscreen app in the first place
            if (WinActive("ahk_id " . ID)) {
              ; Sleep for 10ms or whatever is provided in the 'Delay' key.
              Sleep % %sec%_Delay >= 0 ? %sec%_Delay : 10
              ; Remove borders and title bar
              WinSet, Style, -0xC40000,
              ; Do the move/resize
              WinMove, , , 0, 0, A_ScreenWidth, A_ScreenHeight
              ; Remember that it's now fullscreen
              Win[ID,"Fullscreen"] := true
            }
            else {
              ; Window has not been activated, so keep repeating until it is
              Win[ID].Remove("AutoDone")
            }
          }
        }
        ; If 'AlwaysOnTop' key is set to true
        if (%sec%_AlwaysOnTop = "true") {
          ; Enable always on top
          WinSet, AlwaysOnTop, On
        }
        ; Otherwise if 'AlwaysOnTop' key is set to false (incase it sets it itself)
        else if (%sec%_AlwaysOnTop = "false") {
          ; Disable always on top
          WinSet, AlwaysOnTop, Off
        }
        ; If 'LockMouse' key is set to true..
        if (%sec%_LockMouse = "true") {
          ; Add the window's ID to an array for checking later
          LockCount += 1
          LockWindow%LockCount% := ID
        }
        ; If 'DisableAltTab' key is set to true..
        if (%sec%_DisableAltTab = "true") {
          Win[ID,"DisableAltTab"] := true
        }
        ; If 'DisableWinKey' key is set to true..
        if (%sec%_DisableWinKey = "true") {
          Win[ID,"DisableWinKey"] := true
        }
        ; If 'DisableLaunchKeys' key is set to true..
        if (%sec%_DisableLaunchKeys = "true") {
          Win[ID,"DisableLaunchKeys"] := true
        }
        ; If 'HideTaskbar' key is set to true..
        if (%sec%_HideTaskbar = "true") {
          ; Add the window's ID to an array for checking later
          HideTaskbarCount += 1
          HideTaskbar%HideTaskbarCount% := ID
        }
      }
      ; Loop through all window's that we've been told to lock the mouse to
      Loop %LockCount% {
        ; Get the coordinates and dimensions of this window
        WinGetPos, X, Y, Width, Height, % "ahk_id" . LockWindow%A_Index%
        ; If this window doesn't exist..
        if !WinExist("ahk_id " . LockWindow%A_Index%) and Confine = LockWindow%A_Index% {
          ; Unset confined window
          Confine := 0
          ; Remove cursor constraints
          ClipCursor(false, X, Y, (X+Width), (Y+Height))
        }
        ; If the window does exist..
        else {
          ; If this window is currently active and not confined
          if WinActive("ahk_id " . LockWindow%A_Index%) and Confine <> LockWindow%A_Index% {
            ; Set it as confined.
            Confine := LockWindow%A_Index%
            ; Constrain the cursor
            ClipCursor(true, X, Y, (X+Width), (Y+Height))
          }
          ; If this window is not active but is set as confined
          else if !WinActive("ahk_id " . LockWindow%A_Index%) and Confine = LockWindow%A_Index% {
            ; Unset confined status
            Confine := 0
            ; Remove cursor constraints
            ClipCursor(false, X, Y, (X+Width), (Y+Height))
          }
        }
      }
      ; Loop through all window's that we've been told to hide the taskbar for
      Loop %HideTaskbarCount% {
        ; If this window doesn't exist..
        if !WinExist("ahk_id " . HideTaskbar%A_Index%) {
          WinShow,ahk_class Shell_TrayWnd
          WinShow,Start ahk_class Button
        }
        ; If the window does exist..
        else {
          ; If this window is currently active and taskbar is visible
          if WinActive("ahk_id " . HideTaskbar%A_Index%) and WinExist("ahk_class Shell_TrayWnd") {
            ; Hide the taskbar + Windows button
            WinHide,ahk_class Shell_TrayWnd
            WinHide,Start ahk_class Button
          }
          ; If this window is not active and taskbar is not visible
          else if !WinActive("ahk_id " . HideTaskbar%A_Index%) and !WinExist("ahk_class Shell_TrayWnd") {
            WinShow,ahk_class Shell_TrayWnd
            WinShow,Start ahk_class Button
          }
        }
      }
    }
  }
  ; Go through all the saved windows and free the memory if the window no longer exists
  For key, value in Win
    If !WinExist("ahk_id " . key)
      Win.Remove(key)
  ; Let's sleep so it doesn't hog the CPU
  Sleep 100
}

; Functions

; Modified code by Superfraggle (http://www.autohotkey.com/forum/topic21346.html)
initializeini(inifile) {
  global
  local key,temp
  inisections:=0

  loop,read,%inifile%
  {
    local line := A_Loopreadline
    if SubStr(line,1,1) <> ";"
    if regexmatch(line,"\[(.*)?]")
    {
      inisections+= 1
      section%inisections%:=regexreplace(A_loopreadline,"(\[)(.*)?(])","$2")
      section%inisections%_keys:=0
    }
    else if regexmatch(line,"(\w+)=(.*)")
    {
      section%inisections%_keys+= 1
      key:=section%inisections%_keys
      section%inisections%_key%key%:=regexreplace(A_LoopReadLine,"(\w+)=(.*)","$1")
    }
  }
}

; Modified code by Superfraggle (http://www.autohotkey.com/forum/topic21346.html)
loadini(inifile) {
  global
  local sec,var
  loop,%inisections%
  {
    sec:=A_index
    loop,% section%a_index%_keys
    {
      var:=section%sec% "_" section%sec%_key%A_index%,
      Stringreplace,var,var,%a_space%,,All
      iniread,%var%,%inifile%,% section%sec%,% section%sec%_key%A_index%
    }
  }
}

; Modified code by Superfraggle (http://www.autohotkey.com/forum/topic21346.html)
; Not currently in use
/*
saveini(inifile) {
  global
  local sec,var
  loop,%inisections%
  {
    sec:=A_index
    loop,% section%a_index%_keys
    {
      var:=section%sec% "_" section%sec%_key%A_index%
      Stringreplace,var,var,%a_space%,,All
      var:=%var%
      iniwrite,%var%,%inifile%,% section%sec%,% section%sec%_key%A_index%
    }
  }
}
*/

ClipCursor( Confine=True, x1=0 , y1=0, x2=1, y2=1 ) {
  VarSetCapacity(R,16,0), NumPut(x1,&R+0),NumPut(y1,&R+4),NumPut(x2,&R+8),NumPut(y2,&R+12)
  Return Confine ? DllCall( "ClipCursor", UInt,&R ) : DllCall( "ClipCursor" )
}


; Begin hot-key code

; Disable Windows key if key is set
#If (Win[WinActive("a"),"DisableWinKey"]) or (ToggleTaskbar)
LWin::return
RWin::return

; Disable Alt Tab if key is set
#If (Win[WinActive("a"),"DisableAltTab"])
!Tab::return

; Disable Alt Tab if key is set
#If (Win[WinActive("a"),"DisableLaunchKeys"])
Launch_Mail::return
Launch_Media::return
Launch_App1::return
Launch_App2::return

#If

; Toggle the Taskbar (Ctrl+Alt+F8)
^!F8::
  ToggleTaskbar := !ToggleTaskBar
  if ToggleTaskBar {
    WinHide,ahk_class Shell_TrayWnd ;Kill TaskBar
    WinHide,Start ahk_class Button 
  }
  else {
    WinShow,ahk_class Shell_TrayWnd
    WinShow,Start ahk_class Button 
  }
return

; Kill Active Task (Ctrl+Alt+F4)
^!F4::
  WinGet, active_pid, PID, A
  Process, Close, %active_pid%
return

; Paste Plain text only (Win+V)
#V::SendInput %clipboard%

; Full-screen windowed (Ctrl+Alt+Enter - +Shift for second monitor)
^!Enter::
  WinGet, ID, ID, a
  SetWinDelay, 0
  if (Win[ID]["Fullscreen"]) {
    WinSet, Style, % Win[ID]["Style"], a
    WinMove, a, , % Win[ID]["Left"], % Win[ID]["Top"], % Win[ID]["Width"], % Win[ID]["Height"]
    Win[ID].Remove("Style")
    Win[ID].Remove("Left")
    Win[ID].Remove("Top")
    Win[ID].Remove("Width")
    Win[ID].Remove("Height")
    Win[ID].Remove("Fullscreen")
    ;SetTimer, LockMouse, Off
    ;Confine := false
    ;ClipCursor(false, 0, 0, A_ScreenWidth, A_ScreenHeight)
  }
  else {
    WinGet, Style, Style, a
    WinGetPos, X, Y, Width, Height, a
    Win[ID,"Style"] := Style
    Win[ID,"Left"] := X
    Win[ID,"Top"] := Y
    Win[ID,"Width"] := Width
    Win[ID,"Height"] := Height
    WinSet, Style, -0xC40000, ahk_id %ID%
    if not GetKeyState("Shift")
      WinMove, ahk_id %ID%, , 0, 0, A_ScreenWidth, A_ScreenHeight
    else
      ; It's assumed the second monitor is to the right and 1280x1024 resolution, adjust accordingly.
      WinMove, ahk_id %ID%, , A_ScreenWidth, 0, 1280, 1024
    Win[ID,"Fullscreen"] := true
    ;LockWindow := ID
    ;SetTimer, LockMouse, 50
  }
  ;if (Style & 0xC40000) {
  ;  WinSet, Style, -0xC40000, a
  ;  WinMove, a, , 0, 0, A_ScreenWidth, A_ScreenHeight
  ;}
  ;else {
  ;  WinSet, Style, +0xC40000, a
  ;}
return

; Lock cursor to primary monitor. (Ctrl+Alt+F7)
^!F7::
  ConfineDesktop := !ConfineDesktop
  ClipCursor( ConfineDesktop, 0, 0, A_ScreenWidth, A_ScreenHeight )
return
